//创建进程池
//1.用父进程创建多个子进程
//2.每个子进程与父进程之间用管道联系
#include <iostream>
#include <unistd.h>
#include <cstdio>
#include <cstring>
#include <string>
#include <map>
#include <vector>
#include <ctime>
#include <cstdlib>
#include <sys/types.h>
#include <sys/wait.h>
#define NUM 1024

std::map<int,std::string> tasks{{0,"测试"}, {1,"运行"}, 
                                {2,"BUG"},{3,"崩溃"}};



class channel
{
public:
    channel(int fd, int cmdmode, int id)
    :_fd(fd)
    ,_cmdmode(cmdmode)
    ,_id(id)
    {}

    int getfd() const
    {
        return _fd;
    }
    int getid() const
    {
        return _id;
    }
private:
    int _fd;//每个管道的文件描述符
    int _cmdmode;//每个管道的任务码
    int _id; //每个管道对应的子进程pid
    //std::string _type = "";//任务码对应的具体内容（具体任务）

};

void slaver(int fd)
{
    char buffer[NUM];
    while(true)
    {
        ssize_t n = read(fd, buffer, 1);//等待管道内容，如果没有就阻塞等待
        //如果读端（父进程控制）关闭，则不再继续等待，认为读到了文件尾，则退出函数
        if(n==0)
            return;

        int cmdmode = buffer[0];//将收到的内容接收到cmdmode里

        std::cout << "Child: " << getpid() << " Do: " << tasks[cmdmode] << std::endl;
    }
    

}


void master(std::vector<channel> channels)
{
    int cnt = 5;
    while(cnt)
    {   
        sleep(2);
        //随机值挑选管道（子进程）
        int newpipie = rand()%channels.size();
        //往管道里写入任务码
        int newcmdmode = rand()%4;//4个下标对应设置的4个任务码
        char buffer[NUM];
        buffer[0] = newcmdmode;
        write(channels[newpipie].getfd(), buffer,1);
        cnt--;
    }

}

void Initchannels(std::vector<channel> &channels, std::vector<int> &fatherread)
{
    int cnt = 5;//创建5个子进程和管道
    //第二个子进程开始创建时，会继承父进程的3和4，同时自己获得5（读端）
    //同理第三个子进程会继承3、4、5、6....
    std::vector<int> rabbish_child_fd;//将子进程继承里多出来的不必要端（不必要的文件描述符）给关闭
    while(cnt)
    {
        int pipefd[2] = {0};
        int n = pipe(pipefd);
        if(n != 0)
            exit(0);// 1返回管道创建失败
        fatherread.push_back(pipefd[0]);//每次都保存读端，最后循环结束再删除
        pid_t id = fork();
        if(id == 0)//子进程运行
        {
            for(const auto& e : rabbish_child_fd) close(e);
            close(pipefd[1]);//子进程关闭写端
            slaver(pipefd[0]);//子进程运行指令
            exit(0);//子进程运行完内容就退出
        }
        rabbish_child_fd.push_back(pipefd[0]);
        rabbish_child_fd.push_back(pipefd[1]);
        //父进程运行
        channel temp(pipefd[1],0,id);//任务码开始默认给0
        channels.push_back(temp);
        cnt--;
    }

    for(const auto &e : fatherread)
    {
        close(fatherread[e]);//统一关闭父进程的读端
    }
}